#!/bin/bash

# 个人云笔记一键部署脚本
# Personal Cloud Notes One-Click Deployment Script
# 版本: 3.0 - 最终版本

set -euo pipefail

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# 全局变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_FILE="/var/log/personal-cloud-notes-deploy.log"
BACKUP_DIR="/opt/personal-cloud-notes-backup"
INSTALL_DIR="/opt/personal-cloud-notes"
SERVICE_USER="cloudnotes"
DB_NAME="personal_cloud_notes"
DB_USER="cloudnotes_user"
DB_PASSWORD="WJ20240824"
ADMIN_EMAIL=""
ADMIN_PASSWORD=""
DOMAIN_NAME=""
NODE_VERSION="18"

# 系统信息
OS_NAME=""
PACKAGE_MANAGER=""

# 日志函数
log() {
    local level="$1"
    shift
    local message="$*"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    case "$level" in
        "INFO")
            echo -e "${GREEN}[INFO]${NC} $message"
            ;;
        "WARN")
            echo -e "${YELLOW}[WARN]${NC} $message"
            ;;
        "ERROR")
            echo -e "${RED}[ERROR]${NC} $message"
            ;;
        "SUCCESS")
            echo -e "${GREEN}[SUCCESS]${NC} $message"
            ;;
    esac
    
    echo "[$timestamp] [$level] $message" >> "$LOG_FILE" 2>/dev/null || true
}

# 错误处理函数
error_exit() {
    local line_number="$1"
    local error_code="$2"
    log "ERROR" "脚本在第 $line_number 行出错，退出码: $error_code"
    log "ERROR" "部署失败，请查看日志文件: $LOG_FILE"
    exit "$error_code"
}

# 设置错误陷阱
trap 'error_exit ${LINENO} $?' ERR

# 显示横幅
show_banner() {
    echo -e "${CYAN}"
    cat << 'EOF'
╔══════════════════════════════════════════════════════════════╗
║                个人云笔记一键部署脚本 v3.0                     ║
║            Personal Cloud Notes Deployment v3.0            ║
║                                                              ║
║  特性: 自动安装、配置、诊断、修复                              ║
║  支持: Ubuntu, CentOS, Debian, RHEL                         ║
║  图片处理: 使用Jimp替代Sharp，无编译依赖                       ║
╚══════════════════════════════════════════════════════════════╝
EOF
    echo -e "${NC}"
}

# 检查运行权限
check_permissions() {
    if [[ $EUID -ne 0 ]]; then
        log "ERROR" "此脚本需要root权限运行"
        log "INFO" "请使用: sudo $0"
        exit 1
    fi
}

# 检测系统信息
detect_system() {
    log "INFO" "检测系统信息..."
    
    if [[ -f /etc/os-release ]]; then
        source /etc/os-release
        OS_NAME="$ID"
    elif [[ -f /etc/redhat-release ]]; then
        OS_NAME="centos"
    else
        log "ERROR" "无法检测操作系统类型"
        exit 1
    fi
    
    if command -v apt-get >/dev/null 2>&1; then
        PACKAGE_MANAGER="apt"
    elif command -v yum >/dev/null 2>&1; then
        PACKAGE_MANAGER="yum"
    elif command -v dnf >/dev/null 2>&1; then
        PACKAGE_MANAGER="dnf"
    else
        log "ERROR" "不支持的包管理器"
        exit 1
    fi
    
    log "SUCCESS" "系统检测完成: $OS_NAME ($PACKAGE_MANAGER)"
}

# 检查系统要求
check_requirements() {
    log "INFO" "检查系统要求..."
    
    local mem_total=$(free -m | awk 'NR==2{printf "%.0f", $2}')
    if [[ $mem_total -lt 1024 ]]; then
        log "WARN" "系统内存不足1GB，可能影响性能"
    fi
    
    local disk_free=$(df / | awk 'NR==2{printf "%.0f", $4/1024}')
    if [[ $disk_free -lt 2048 ]]; then
        log "ERROR" "磁盘空间不足2GB，无法继续安装"
        exit 1
    fi
    
    if ! ping -c 1 google.com >/dev/null 2>&1 && ! ping -c 1 baidu.com >/dev/null 2>&1; then
        log "ERROR" "网络连接失败，无法下载依赖包"
        exit 1
    fi
    
    log "SUCCESS" "系统要求检查通过"
}

# 修复主机名解析问题
fix_hostname_resolution() {
    log "INFO" "修复主机名解析问题..."
    
    local hostname=$(hostname)
    local hosts_file="/etc/hosts"
    
    if ! grep -q "127.0.0.1.*$hostname" "$hosts_file"; then
        echo "127.0.0.1 $hostname" >> "$hosts_file"
    fi
    
    if ! grep -q "127.0.0.1.*localhost" "$hosts_file"; then
        sed -i '1i127.0.0.1 localhost' "$hosts_file"
    fi
    
    log "SUCCESS" "主机名解析修复完成"
}

# 等待并处理包管理器锁定
wait_for_package_manager() {
    if [[ "$PACKAGE_MANAGER" == "apt" ]]; then
        log "INFO" "检查包管理器锁定状态..."
        
        systemctl stop unattended-upgrades >/dev/null 2>&1 || true
        systemctl disable unattended-upgrades >/dev/null 2>&1 || true
        
        killall -9 unattended-upgrade >/dev/null 2>&1 || true
        killall -9 apt >/dev/null 2>&1 || true
        killall -9 apt-get >/dev/null 2>&1 || true
        killall -9 dpkg >/dev/null 2>&1 || true
        
        sleep 2
        
        rm -f /var/lib/dpkg/lock-frontend >/dev/null 2>&1 || true
        rm -f /var/lib/dpkg/lock >/dev/null 2>&1 || true
        rm -f /var/cache/apt/archives/lock >/dev/null 2>&1 || true
        rm -f /var/lib/apt/lists/lock >/dev/null 2>&1 || true
        
        dpkg --configure -a >/dev/null 2>&1 || true
        
        log "SUCCESS" "包管理器锁定处理完成"
    fi
}

# 更新系统包
update_system() {
    log "INFO" "更新系统包..."
    
    wait_for_package_manager
    
    case "$PACKAGE_MANAGER" in
        "apt")
            export DEBIAN_FRONTEND=noninteractive
            apt-get update -y
            apt-get upgrade -y
            apt-get install -y curl wget gnupg2 software-properties-common apt-transport-https ca-certificates lsb-release build-essential
            ;;
        "yum")
            yum update -y
            yum install -y curl wget epel-release gcc gcc-c++ make
            ;;
        "dnf")
            dnf update -y
            dnf install -y curl wget gcc gcc-c++ make
            ;;
    esac
    
    log "SUCCESS" "系统包更新完成"
}

# 安装Node.js
install_nodejs() {
    log "INFO" "安装Node.js $NODE_VERSION..."
    
    if command -v node >/dev/null 2>&1; then
        local current_version=$(node --version | cut -d'v' -f2 | cut -d'.' -f1)
        if [[ "$current_version" -ge "$NODE_VERSION" ]]; then
            log "INFO" "Node.js已安装，版本: $(node --version)"
            return
        fi
    fi
    
    curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash -
    
    wait_for_package_manager
    
    case "$PACKAGE_MANAGER" in
        "apt")
            apt-get install -y nodejs
            ;;
        "yum"|"dnf")
            $PACKAGE_MANAGER install -y nodejs npm
            ;;
    esac
    
    if ! command -v node >/dev/null 2>&1; then
        log "ERROR" "Node.js安装失败"
        exit 1
    fi
    
    npm install -g pm2
    
    log "SUCCESS" "Node.js安装完成，版本: $(node --version)"
}

# 安装MySQL
install_mysql() {
    log "INFO" "安装MySQL..."
    
    if command -v mysql >/dev/null 2>&1; then
        log "INFO" "MySQL已安装"
        if [[ ! -f /root/.mysql_root_password ]]; then
            mysql_secure_installation_auto
        fi
        return
    fi
    
    wait_for_package_manager
    
    case "$PACKAGE_MANAGER" in
        "apt")
            export DEBIAN_FRONTEND=noninteractive
            apt-get install -y mysql-server mysql-client
            ;;
        "yum")
            yum install -y mysql-server mysql
            ;;
        "dnf")
            dnf install -y mysql-server mysql
            ;;
    esac
    
    systemctl enable mysql || systemctl enable mysqld
    systemctl start mysql || systemctl start mysqld
    
    sleep 5
    mysql_secure_installation_auto
    
    log "SUCCESS" "MySQL安装完成"
}

# 自动化MySQL安全配置
mysql_secure_installation_auto() {
    log "INFO" "配置MySQL安全设置..."
    
    local mysql_root_password="$DB_PASSWORD"
    
    systemctl start mysql >/dev/null 2>&1 || true
    sleep 3
    
    if [[ -f /etc/mysql/debian.cnf ]]; then
        mysql --defaults-file=/etc/mysql/debian.cnf <<EOF
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '$mysql_root_password';
DELETE FROM mysql.user WHERE User='';
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
EOF
    else
        systemctl stop mysql >/dev/null 2>&1 || true
        sleep 2
        
        cat > /tmp/mysql-init.sql <<EOF
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '$mysql_root_password';
DELETE FROM mysql.user WHERE User='';
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
EOF
        
        mysqld --init-file=/tmp/mysql-init.sql --user=mysql &
        local mysqld_pid=$!
        sleep 10
        kill $mysqld_pid >/dev/null 2>&1 || true
        sleep 3
        rm -f /tmp/mysql-init.sql
        systemctl start mysql
        sleep 3
    fi

    cat > /root/.my.cnf <<EOF
[client]
user=root
password=$mysql_root_password
EOF
    chmod 600 /root/.my.cnf
    echo "$mysql_root_password" > /root/.mysql_root_password
    chmod 600 /root/.mysql_root_password
    
    if mysql -u root -p"$mysql_root_password" -e "SELECT 1;" >/dev/null 2>&1; then
        log "SUCCESS" "MySQL安全配置完成"
    else
        log "ERROR" "MySQL密码连接测试失败"
        exit 1
    fi
}

# 安装Nginx
install_nginx() {
    log "INFO" "安装Nginx..."
    
    if command -v nginx >/dev/null 2>&1; then
        log "INFO" "Nginx已安装"
        return
    fi
    
    wait_for_package_manager
    
    case "$PACKAGE_MANAGER" in
        "apt")
            apt-get install -y nginx
            ;;
        "yum"|"dnf")
            $PACKAGE_MANAGER install -y nginx
            ;;
    esac
    
    systemctl enable nginx
    systemctl start nginx
    
    log "SUCCESS" "Nginx安装完成"
}

# 创建系统用户
create_system_user() {
    log "INFO" "创建系统用户 $SERVICE_USER..."
    
    if id "$SERVICE_USER" >/dev/null 2>&1; then
        log "INFO" "用户 $SERVICE_USER 已存在"
        return
    fi
    
    useradd -r -s /bin/bash -d "$INSTALL_DIR" -m "$SERVICE_USER"
    
    log "SUCCESS" "系统用户 $SERVICE_USER 创建完成"
}

# 创建数据库和用户
setup_database() {
    log "INFO" "设置数据库..."
    
    local mysql_root_password="$DB_PASSWORD"
    
    mysql -u root -p"$mysql_root_password" <<EOF
CREATE DATABASE IF NOT EXISTS $DB_NAME CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '$DB_USER'@'localhost' IDENTIFIED BY '$DB_PASSWORD';
GRANT ALL PRIVILEGES ON $DB_NAME.* TO '$DB_USER'@'localhost';
FLUSH PRIVILEGES;
EOF

    log "SUCCESS" "数据库设置完成"
}

# 创建缺失的JS文件
create_missing_js_files() {
    log "INFO" "创建缺失的JS文件..."
    
    cd "$INSTALL_DIR"
    
    # 确保目录存在
    mkdir -p public/js/utils
    mkdir -p public/js/components
    mkdir -p public/css
    mkdir -p public/static/image
    
    # 创建基础的utils文件
    if [[ ! -f "public/js/utils/api.js" ]]; then
        cat > "public/js/utils/api.js" <<'EOF'
/**
 * API工具类
 */
class API {
    constructor() {
        this.baseURL = '/api';
        this.token = localStorage.getItem('token');
    }

    async request(endpoint, options = {}) {
        const url = `${this.baseURL}${endpoint}`;
        const config = {
            headers: {
                'Content-Type': 'application/json',
                ...options.headers
            },
            ...options
        };

        if (this.token) {
            config.headers.Authorization = `Bearer ${this.token}`;
        }

        try {
            const response = await fetch(url, config);
            
            if (!response.ok) {
                throw new Error(`HTTP error! status: ${response.status}`);
            }
            
            return await response.json();
        } catch (error) {
            console.error('API request failed:', error);
            throw error;
        }
    }

    async get(endpoint) {
        return this.request(endpoint, { method: 'GET' });
    }

    async post(endpoint, data) {
        return this.request(endpoint, {
            method: 'POST',
            body: JSON.stringify(data)
        });
    }

    setToken(token) {
        this.token = token;
        if (token) {
            localStorage.setItem('token', token);
        } else {
            localStorage.removeItem('token');
        }
    }
}

window.api = new API();
EOF
    fi

    if [[ ! -f "public/js/utils/auth.js" ]]; then
        cat > "public/js/utils/auth.js" <<'EOF'
/**
 * 认证工具类
 */
class Auth {
    constructor() {
        this.token = localStorage.getItem('token');
        this.user = JSON.parse(localStorage.getItem('user') || 'null');
    }

    isAuthenticated() {
        return !!this.token;
    }

    async login(email, password) {
        try {
            const response = await api.post('/auth/login', { email, password });
            
            if (response.success) {
                this.token = response.data.token;
                this.user = response.data.user;
                
                localStorage.setItem('token', this.token);
                localStorage.setItem('user', JSON.stringify(this.user));
                
                api.setToken(this.token);
                
                return response;
            }
            
            throw new Error(response.message || '登录失败');
        } catch (error) {
            console.error('Login failed:', error);
            throw error;
        }
    }

    logout() {
        this.token = null;
        this.user = null;
        
        localStorage.removeItem('token');
        localStorage.removeItem('user');
        
        api.setToken(null);
        
        window.location.href = '/';
    }
}

window.auth = new Auth();
EOF
    fi

    if [[ ! -f "public/js/utils/notification.js" ]]; then
        cat > "public/js/utils/notification.js" <<'EOF'
/**
 * 通知工具类
 */
class Notification {
    constructor() {
        this.container = document.getElementById('notification');
        this.message = document.getElementById('notification-message');
        this.icon = document.getElementById('notification-icon');
        this.closeBtn = document.getElementById('notification-close');
        
        if (this.closeBtn) {
            this.closeBtn.addEventListener('click', () => this.hide());
        }
    }

    show(message, type = 'info', duration = 3000) {
        if (!this.container) return;

        this.message.textContent = message;
        
        const icons = {
            success: '<i class="fa fa-check-circle text-green-500"></i>',
            error: '<i class="fa fa-exclamation-circle text-red-500"></i>',
            warning: '<i class="fa fa-exclamation-triangle text-yellow-500"></i>',
            info: '<i class="fa fa-info-circle text-blue-500"></i>'
        };
        
        this.icon.innerHTML = icons[type] || icons.info;
        
        this.container.classList.remove('hidden');
        
        if (duration > 0) {
            setTimeout(() => this.hide(), duration);
        }
    }

    hide() {
        if (this.container) {
            this.container.classList.add('hidden');
        }
    }
}

window.notification = new Notification();
EOF
    fi

    # 创建基础的组件文件
    local components=("login" "search" "storage" "rich-editor" "dashboard" "notes-manager")
    for component in "${components[@]}"; do
        if [[ ! -f "public/js/components/${component}.js" ]]; then
            cat > "public/js/components/${component}.js" <<EOF
/**
 * ${component^} 组件
 */
class ${component^}Component {
    constructor() {
        this.init();
    }

    init() {
        console.log('${component^} component initialized');
    }
}

window.${component}Component = ${component^}Component;
EOF
        fi
    done
    
    log "SUCCESS" "缺失的JS文件创建完成"
}

# 部署应用代码
deploy_application() {
    log "INFO" "部署应用代码..."
    
    mkdir -p "$INSTALL_DIR"
    
    local source_dir=""
    if [[ -d "$SCRIPT_DIR" ]] && [[ -f "$SCRIPT_DIR/server/app.js" ]]; then
        source_dir="$SCRIPT_DIR"
    else
        log "ERROR" "找不到应用源码目录"
        exit 1
    fi
    
    cp -r "$source_dir/"* "$INSTALL_DIR/"
    
    # 删除部署脚本和临时文件
    rm -f "$INSTALL_DIR"/deploy*.sh
    rm -f "$INSTALL_DIR"/fix*.sh
    rm -f "$INSTALL_DIR"/diagnose*.sh
    rm -f "$INSTALL_DIR"/quick*.sh
    rm -f "$INSTALL_DIR"/run*.sh
    rm -f "$INSTALL_DIR"/test*.sh
    
    chown -R "$SERVICE_USER:$SERVICE_USER" "$INSTALL_DIR"
    chmod -R 755 "$INSTALL_DIR"
    
    cd "$INSTALL_DIR"
    
    # 清理可能存在的node_modules
    rm -rf node_modules package-lock.json
    
    # 安装依赖
    sudo -u "$SERVICE_USER" npm install --production
    
    # 创建缺失的JS文件
    create_missing_js_files
    
    log "SUCCESS" "应用代码部署完成"
}

# 配置应用
configure_application() {
    log "INFO" "配置应用..."
    
    cat > "$INSTALL_DIR/.env" <<EOF
# 数据库配置
DB_HOST=127.0.0.1
DB_PORT=3306
DB_NAME=$DB_NAME
DB_USER=$DB_USER
DB_PASSWORD=$DB_PASSWORD

# JWT配置
JWT_SECRET=$(openssl rand -base64 64)

# 应用配置
NODE_ENV=production
PORT=3000

# 管理员配置
ADMIN_EMAIL=$ADMIN_EMAIL
ADMIN_PASSWORD=$ADMIN_PASSWORD

# 文件上传配置
UPLOAD_PATH=$INSTALL_DIR/uploads
MAX_FILE_SIZE=104857600

# 日志配置
LOG_LEVEL=info
LOG_FILE=$INSTALL_DIR/logs/app.log
EOF

    chown "$SERVICE_USER:$SERVICE_USER" "$INSTALL_DIR/.env"
    chmod 600 "$INSTALL_DIR/.env"
    
    mkdir -p "$INSTALL_DIR/uploads" "$INSTALL_DIR/logs" "$INSTALL_DIR/data"
    chown -R "$SERVICE_USER:$SERVICE_USER" "$INSTALL_DIR/uploads" "$INSTALL_DIR/logs" "$INSTALL_DIR/data"
    
    log "SUCCESS" "应用配置完成"
}

# 配置Nginx
configure_nginx() {
    log "INFO" "配置Nginx..."
    
    cat > "/etc/nginx/sites-available/personal-cloud-notes" <<'EOF'
server {
    listen 80;
    server_name _;
    
    # 安全头
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Referrer-Policy "strict-origin-when-cross-origin";
    
    # 禁用HTTPS重定向相关头
    add_header Cross-Origin-Opener-Policy "unsafe-none";
    
    # 根目录设置
    root /opt/personal-cloud-notes/public;
    index index.html;
    
    # 静态资源 - 直接从public目录服务
    location /static/ {
        alias /opt/personal-cloud-notes/public/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Access-Control-Allow-Origin "*";
        try_files $uri $uri/ =404;
    }
    
    location /js/ {
        alias /opt/personal-cloud-notes/public/js/;
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Access-Control-Allow-Origin "*";
        try_files $uri $uri/ =404;
    }
    
    location /css/ {
        alias /opt/personal-cloud-notes/public/css/;
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Access-Control-Allow-Origin "*";
        try_files $uri $uri/ =404;
    }
    
    # 上传文件
    location /uploads/ {
        alias /opt/personal-cloud-notes/uploads/;
        expires 1y;
        add_header Cache-Control "public";
        add_header Access-Control-Allow-Origin "*";
        try_files $uri $uri/ =404;
    }
    
    # API路由
    location /api/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        
        # 超时设置
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
        
        # 缓冲设置
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
    }
    
    # 健康检查
    location /health {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    
    # 主页面和SPA路由
    location / {
        try_files $uri $uri/ @app;
    }
    
    # 应用代理
    location @app {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
        
        # 超时设置
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
    
    # 文件上传大小限制
    client_max_body_size 100M;
    
    # 日志
    access_log /var/log/nginx/personal-cloud-notes.access.log;
    error_log /var/log/nginx/personal-cloud-notes.error.log;
}
EOF

    if [[ -d "/etc/nginx/sites-enabled" ]]; then
        ln -sf "/etc/nginx/sites-available/personal-cloud-notes" "/etc/nginx/sites-enabled/"
        rm -f "/etc/nginx/sites-enabled/default"
    else
        cp "/etc/nginx/sites-available/personal-cloud-notes" "/etc/nginx/conf.d/personal-cloud-notes.conf"
    fi
    
    if nginx -t; then
        systemctl restart nginx
        sleep 2
        if systemctl is-active --quiet nginx; then
            log "SUCCESS" "Nginx配置完成"
        else
            log "ERROR" "Nginx重启失败"
            exit 1
        fi
    else
        log "ERROR" "Nginx配置测试失败"
        exit 1
    fi
}

# 创建systemd服务
create_systemd_service() {
    log "INFO" "创建systemd服务..."
    
    cat > "/etc/systemd/system/personal-cloud-notes.service" <<EOF
[Unit]
Description=Personal Cloud Notes Application
After=network.target mysql.service
Wants=mysql.service

[Service]
Type=simple
User=$SERVICE_USER
Group=$SERVICE_USER
WorkingDirectory=$INSTALL_DIR
Environment=NODE_ENV=production
ExecStart=/usr/bin/node server/app.js
ExecReload=/bin/kill -HUP \$MAINPID
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=personal-cloud-notes

NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=$INSTALL_DIR

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    systemctl enable personal-cloud-notes
    
    log "SUCCESS" "systemd服务创建完成"
}

# 初始化数据库
initialize_database() {
    log "INFO" "初始化数据库..."
    
    cd "$INSTALL_DIR"
    
    # 创建完整的数据库架构
    mysql -u "$DB_USER" -p"$DB_PASSWORD" -D "$DB_NAME" <<'EOF'
-- 创建用户表
CREATE TABLE IF NOT EXISTS users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(255) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    nickname VARCHAR(100) DEFAULT NULL,
    role ENUM('admin', 'user') DEFAULT 'user',
    avatar VARCHAR(500) DEFAULT NULL,
    storage_used BIGINT DEFAULT 0,
    storage_limit BIGINT DEFAULT 32212254720,
    is_active TINYINT(1) DEFAULT 1,
    last_login_at TIMESTAMP NULL DEFAULT NULL,
    last_login_ip VARCHAR(45) DEFAULT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_email (email),
    INDEX idx_role (role),
    INDEX idx_is_active (is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 创建笔记表
CREATE TABLE IF NOT EXISTS notes (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    title VARCHAR(255) NOT NULL,
    content LONGTEXT,
    tags JSON,
    is_public TINYINT(1) DEFAULT 0,
    is_deleted TINYINT(1) DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    deleted_at TIMESTAMP NULL DEFAULT NULL,
    INDEX idx_user_id (user_id),
    INDEX idx_title (title),
    INDEX idx_is_deleted (is_deleted),
    INDEX idx_created_at (created_at),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 创建文件表
CREATE TABLE IF NOT EXISTS files (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    filename VARCHAR(255) NOT NULL,
    original_name VARCHAR(255) NOT NULL,
    file_path VARCHAR(500) NOT NULL,
    file_size BIGINT NOT NULL,
    mime_type VARCHAR(100) NOT NULL,
    is_deleted TINYINT(1) DEFAULT 0,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_user_id (user_id),
    INDEX idx_filename (filename),
    INDEX idx_is_deleted (is_deleted),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 创建标签表
CREATE TABLE IF NOT EXISTS tags (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    name VARCHAR(50) NOT NULL,
    color VARCHAR(7) DEFAULT '#007bff',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY unique_user_tag (user_id, name),
    INDEX idx_user_id (user_id),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 创建笔记标签关联表
CREATE TABLE IF NOT EXISTS note_tags (
    id INT AUTO_INCREMENT PRIMARY KEY,
    note_id INT NOT NULL,
    tag_id INT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY unique_note_tag (note_id, tag_id),
    INDEX idx_note_id (note_id),
    INDEX idx_tag_id (tag_id),
    FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE,
    FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 创建设置表
CREATE TABLE IF NOT EXISTS settings (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    setting_key VARCHAR(100) NOT NULL,
    setting_value TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY unique_user_setting (user_id, setting_key),
    INDEX idx_user_id (user_id),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 创建活动日志表
CREATE TABLE IF NOT EXISTS activity_logs (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT,
    action VARCHAR(100) NOT NULL,
    resource_type VARCHAR(50),
    resource_id INT,
    details JSON,
    ip_address VARCHAR(45),
    user_agent TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_user_id (user_id),
    INDEX idx_action (action),
    INDEX idx_created_at (created_at),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
EOF

    # 创建默认管理员用户
    create_admin_user
    
    log "SUCCESS" "数据库初始化完成"
}

# 创建默认管理员用户
create_admin_user() {
    log "INFO" "创建默认管理员用户..."
    
    cd "$INSTALL_DIR"
    
    # 创建用户创建脚本
    cat > create_admin_user.js <<'EOF'
require('dotenv').config();
const bcrypt = require('bcryptjs');
const mysql = require('mysql2/promise');

async function createAdminUser() {
    let connection;
    try {
        connection = await mysql.createConnection({
            host: process.env.DB_HOST || '127.0.0.1',
            port: process.env.DB_PORT || 3306,
            user: process.env.DB_USER || 'cloudnotes_user',
            password: process.env.DB_PASSWORD || 'WJ20240824',
            database: process.env.DB_NAME || 'personal_cloud_notes'
        });

        // 检查是否已存在管理员用户
        const [existingUsers] = await connection.execute(
            'SELECT COUNT(*) as count FROM users WHERE role = ?',
            ['admin']
        );

        if (existingUsers[0].count > 0) {
            console.log('管理员用户已存在，跳过创建');
            return;
        }

        // 创建默认管理员用户
        const adminEmail = process.env.ADMIN_EMAIL || 'admin@123.com';
        const adminPassword = process.env.ADMIN_PASSWORD || 'admin123456';
        const hashedPassword = await bcrypt.hash(adminPassword, 10);

        await connection.execute(
            `INSERT INTO users (email, password, nickname, role, is_active, created_at) 
             VALUES (?, ?, ?, ?, ?, NOW())`,
            [adminEmail, hashedPassword, '管理员', 'admin', 1]
        );

        console.log('默认管理员用户创建成功');
        console.log('邮箱:', adminEmail);
        console.log('密码:', adminPassword);

    } catch (error) {
        console.error('创建管理员用户失败:', error.message);
        throw error;
    } finally {
        if (connection) {
            await connection.end();
        }
    }
}

createAdminUser();
EOF

    # 运行用户创建脚本
    sudo -u "$SERVICE_USER" node create_admin_user.js
    rm -f create_admin_user.js
    
    log "SUCCESS" "默认管理员用户创建完成"
}

# 启动服务
start_services() {
    log "INFO" "启动服务..."
    
    systemctl start personal-cloud-notes
    
    sleep 5
    if systemctl is-active --quiet personal-cloud-notes; then
        log "SUCCESS" "应用服务启动成功"
    else
        log "ERROR" "应用服务启动失败"
        systemctl status personal-cloud-notes --no-pager
        journalctl -u personal-cloud-notes -n 20 --no-pager
        exit 1
    fi
    
    # 安装网络工具
    if ! command -v netstat >/dev/null 2>&1; then
        wait_for_package_manager
        case "$PACKAGE_MANAGER" in
            "apt")
                apt-get install -y net-tools
                ;;
            "yum"|"dnf")
                $PACKAGE_MANAGER install -y net-tools
                ;;
        esac
    fi
    
    # 检查端口监听
    if netstat -tlnp 2>/dev/null | grep -q ":3000.*LISTEN"; then
        log "SUCCESS" "应用正在监听端口3000"
    else
        log "ERROR" "应用未监听端口3000"
        exit 1
    fi
    
    if netstat -tlnp 2>/dev/null | grep -q ":80.*LISTEN"; then
        log "SUCCESS" "Nginx正在监听端口80"
    else
        log "ERROR" "Nginx未监听端口80"
        exit 1
    fi
}

# 运行健康检查
health_check() {
    log "INFO" "运行健康检查..."
    
    local max_attempts=30
    local attempt=1
    
    while [[ $attempt -le $max_attempts ]]; do
        if curl -f -s http://localhost/health >/dev/null; then
            log "SUCCESS" "健康检查通过"
            return 0
        fi
        
        log "INFO" "健康检查失败，重试 $attempt/$max_attempts"
        sleep 2
        ((attempt++))
    done
    
    log "WARN" "健康检查失败，但部署可能仍然成功"
    return 1
}

# 配置防火墙
configure_firewall() {
    log "INFO" "配置防火墙..."
    
    if command -v ufw >/dev/null 2>&1; then
        ufw --force enable
        ufw allow 22/tcp
        ufw allow 80/tcp
        ufw allow 443/tcp
    elif command -v firewall-cmd >/dev/null 2>&1; then
        systemctl enable firewalld
        systemctl start firewalld
        firewall-cmd --permanent --add-service=ssh
        firewall-cmd --permanent --add-service=http
        firewall-cmd --permanent --add-service=https
        firewall-cmd --reload
    fi
    
    log "SUCCESS" "防火墙配置完成"
}

# 显示部署结果
show_deployment_result() {
    echo
    echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
    echo -e "${GREEN}║                    部署完成！                                  ║${NC}"
    echo -e "${GREEN}║                 Deployment Complete!                        ║${NC}"
    echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"
    echo
    
    log "SUCCESS" "个人云笔记部署成功！"
    echo
    echo -e "${CYAN}访问信息 / Access Information:${NC}"
    echo -e "  网站地址 / Website: ${GREEN}http://${DOMAIN_NAME:-$(hostname -I | awk '{print $1}')}${NC}"
    echo -e "  管理员邮箱 / Admin Email: ${GREEN}$ADMIN_EMAIL${NC}"
    echo -e "  管理员密码 / Admin Password: ${GREEN}$ADMIN_PASSWORD${NC}"
    echo
    echo -e "${CYAN}服务管理 / Service Management:${NC}"
    echo -e "  启动服务: ${YELLOW}systemctl start personal-cloud-notes${NC}"
    echo -e "  停止服务: ${YELLOW}systemctl stop personal-cloud-notes${NC}"
    echo -e "  重启服务: ${YELLOW}systemctl restart personal-cloud-notes${NC}"
    echo -e "  查看状态: ${YELLOW}systemctl status personal-cloud-notes${NC}"
    echo -e "  查看日志: ${YELLOW}journalctl -u personal-cloud-notes -f${NC}"
    echo
    echo -e "${CYAN}重要文件位置 / Important File Locations:${NC}"
    echo -e "  应用目录: ${YELLOW}$INSTALL_DIR${NC}"
    echo -e "  配置文件: ${YELLOW}$INSTALL_DIR/.env${NC}"
    echo -e "  日志文件: ${YELLOW}$LOG_FILE${NC}"
    echo
    echo -e "${CYAN}数据库信息 / Database Information:${NC}"
    echo -e "  数据库名: ${YELLOW}$DB_NAME${NC}"
    echo -e "  数据库用户: ${YELLOW}$DB_USER${NC}"
    echo -e "  MySQL Root密码: ${YELLOW}/root/.mysql_root_password${NC}"
    echo
    echo -e "${CYAN}技术特性 / Technical Features:${NC}"
    echo -e "  图片处理: ${YELLOW}Jimp (纯JavaScript，无编译依赖)${NC}"
    echo -e "  缩略图格式: ${YELLOW}JPEG (兼容性更好)${NC}"
    echo -e "  部署方式: ${YELLOW}一键部署，自动修复${NC}"
    echo
}

# 收集用户输入
collect_user_input() {
    echo -e "${CYAN}请提供以下配置信息 / Please provide configuration information:${NC}"
    echo
    
    while [[ -z "$ADMIN_EMAIL" ]]; do
        read -p "管理员邮箱 / Admin Email: " ADMIN_EMAIL
        if [[ ! "$ADMIN_EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
            echo -e "${RED}请输入有效的邮箱地址${NC}"
            ADMIN_EMAIL=""
        fi
    done
    
    while [[ -z "$ADMIN_PASSWORD" ]]; do
        read -s -p "管理员密码 / Admin Password (至少6位): " ADMIN_PASSWORD
        echo
        if [[ ${#ADMIN_PASSWORD} -lt 6 ]]; then
            echo -e "${RED}密码至少需要6位字符${NC}"
            ADMIN_PASSWORD=""
        fi
    done
    
    read -p "域名 / Domain Name (可选，直接回车跳过): " DOMAIN_NAME
    
    echo
}

# 主函数
main() {
    show_banner
    check_permissions
    
    touch "$LOG_FILE"
    chmod 644 "$LOG_FILE"
    
    log "INFO" "开始部署个人云笔记系统..."
    
    collect_user_input
    detect_system
    check_requirements
    fix_hostname_resolution
    
    update_system
    install_nodejs
    install_mysql
    install_nginx
    
    create_system_user
    setup_database
    
    deploy_application
    configure_application
    configure_nginx
    create_systemd_service
    
    initialize_database
    start_services
    
    configure_firewall
    
    if ! health_check; then
        log "WARN" "健康检查失败，但部署可能仍然成功"
    fi
    
    show_deployment_result
    
    log "SUCCESS" "部署脚本执行完成！"
}

# 脚本入口点
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi